TypeScript でゼロから作るパーサコンビネータ - blog.livewing.net
実装
code:型定義.ts
export type ParserInput = readonly string[];
export interface ParseSuccess<T> {
result: "success";
data: T;
rest: ParserInput;
}
export interface ParseFail {
result: "fail";
}
export type ParserOutput<T> = Readonly<ParseSuccess<T> | ParseFail>;
export type Parser<T> = (input: ParserInput) => ParserOutput<T>;
export type ParsedData<P> => P extends Parser<infer T> ? T : never;
parsers
anyChar: Parser<string> 任意の1文字
eof: Parser<null> 終端
char: <S extends string>(c: S) => Parser<S> 特定の文字c
str: <S extends string>(s: S) => Parser<S> 特定の文字列
is: <S extends string>(fn: (c: string) => c is S) => Parser<S>
条件fnを満たす文字
charの一般化
alpha: Parser<Alphabet>
/[a-zA-Z]/にマッチ
type Alphabet = UpperAlphabet | LowerAlphabet
upperAlpha: Parser<UpperAlphabet>
/[A-Z]/にマッチ
type UpperAlphabet = Uowercase<LowerAlphabet>
lowerAlpha: Parser<LowerAlphabet>
/[a-z]/にマッチ
LowerAlphabetの型定義は略
digit: Parser<Digit>
/[0-9]/にマッチ
Digitの型定義は略
combinators
not: (p: Parser<unknown>) => Parser<null>
pが失敗した時成功
文字を消費しない
or: <T>(ps: Parser<T>[]) => Parser<T>
最初に成功したparserを返す
cat: <Parsers extends Parser<unknown>[]>(ps: [...Parsers]) => Parser<{ [K in keyof Parsers]: ParsedData<Parsers[K]>}>
順番に渡し、成功したらすべてのpsの結果を返す
rep: <T>(p: Parser<T>, min?: number, max?: number) => Parser<T[]>
繰り返し
map: <T, U>(p: Parser<T>, fn: (t: T) => U) => Parser<U>
型変換
opt: <T>(p: Parser<T>) => Parser<Option<T>>
0~1回の繰り返し
type Option<T> = { status: "some"; value: T } | { status: "none"; }
diff: <T, U>(p: Parser<T>, q: Parser<U>) => Parser<T>
差分演算子、pが成功してqが失敗したときのみ成功する
notで実装可
list: <T>(p: Parser<T>, delimiter: Parser<unknown>) => Parser<T[]>
delimiterで区切った文字列をparseする
例:
四則演算
JSON parser